/* 
 * Copyright (C) 2005, 2006 Liu Di <liudidi@gmail.com> 
 *
 * Copyright (C) 2007 Wei Lian <lianwei3@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "sopfork.h"
#include "header.h"
#include "playfork.h"
#include "utils.h"
#include "tabwidget.h"
#include "pageplay.h"
#include "mystatusbar.h"
#include "record.h"
#include "mainwindow.h"

SopFork::SopFork (QWidget * widget, QString url, QString name, QString type,
		  QWidget * parent, const char *name2):
QObject (parent, name2),
channelurl (url),
channelname (name),
channeltype (type),
tabwidget (static_cast < TabWidget * >(parent))
{
    ///sop process
    sop = new QProcess (this);
    connect (sop, SIGNAL (readyReadStdout ()), this, SLOT (parseStdout ()));
    connect (sop, SIGNAL (processExited ()), this, SLOT (onSopExit ()));
    ///timer
    echotimer = new QTimer (this);
    connect (echotimer, SIGNAL (timeout ()), this, SLOT (echo ()));
    ///socket notifier
    snstatus = NULL;
    ///append widget to listpage
    listpage.append (widget);
    ///update message
    message = tr ("Connecting...");
    ///fork sop 
    forkSop ();
}


SopFork::~SopFork ()
{
    if (snstatus)
	delete snstatus;
    killSop ();
}


////fork new process
bool
SopFork::forkSop ()
{
    ///select inport and outport number
    int i, j, sock;
    while (1) {
	i = rand () % (65536 - 10000) + 10000;	////10000 to 65535
	sock = connect_to_server ("127.0.0.1", i);
	if (sock == -1)
	    break;
	else if (sock >= 0)
	    ::close (sock);
    }
    sprintf (inport, "%d", i);
    while (1) {
	j = rand () % (65536 - 10000) + 10000;
	sock = connect_to_server ("127.0.0.1", j);
	if (sock == -1 && j != i)
	    break;
	else if (sock >= 0)
	    ::close (sock);
    }
    sprintf (outport, "%d", j);
    ////fork sop process    
    sop->clearArguments ();
    sop->addArgument ("sp-sc");
    sop->addArgument (channelurl);
    sop->addArgument (inport);
    sop->addArgument (outport);
    return sop->start ();
}



////kill process
void
SopFork::killSop ()
{
    /*    if (sop->isRunning()) {
       //      sop->tryTerminate ();
       sop->kill();
       } */
    char str[256];
    strcpy (str, sop->arguments ().join (" ").ascii ());
    killProcess (str, sop->processIdentifier (), sop->processIdentifier () + 10);

}



/////////////slots
void
SopFork::onSopExit ()
{
    ///restart sop
    if (forkSop ()) {
    } else
	fprintf (stderr, "failed to launch sp-sc!\n");
}


void
SopFork::parseStdout ()
{
    QString str = QString (sop->readStdout ());

    if (snstatus == 0) {
	if (str.contains ("hook_sc") || str.contains ("downloadRate=")) {
	    //create socket
	    int sockfd = connect_to_server ("127.0.0.1", atoi (outport));
	    if (sockfd < 0) {
		fprintf (stderr, "failed to create socket, return err %d\n", sockfd);
		return;
	    }
	    ///bind QSocketNotifier to socket
	    snstatus = new QSocketNotifier (sockfd, QSocketNotifier::Read, this);
	    connect (snstatus, SIGNAL (activated (int)), SLOT (streamReady (int)));
	    write (sockfd, "state\ns\n", sizeof ("state\ns\n"));
	    write (sockfd, "state\ns\n", sizeof ("state\ns\n"));
	    ///launch player, should be executed after registering snstatus
	    for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
		if (static_cast < MyHBox * >(wd)->pagetype == "play"
		    && static_cast < PagePlay * >(wd)->buttonplayer->isOn ())
		    static_cast < PagePlay * >(wd)->onButtonPlayerToggled (true);
	    ///update message
	    message = "data";
	} else if (str.contains ("detect MTU")) {
	    ///update message
	    message = tr ("Waiting...");
	    ///show message on statusbar
	    for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
		if (tabwidget->indexOf (wd) == tabwidget->currentPageIndex ()) {
		    static_cast < MainWindow * >(qApp->mainWidget ())
			->statusbar->showMessage (message);
		    break;
		}
	}
    }
}


void
SopFork::streamReady (int fd)
{
    char buff[64];
    memset (buff, 0, sizeof (buff));

    int red = 0, size, ret;
    size = sizeof (buff);
    while (1) {
	ret =::read (fd, buff + red, size);
	if (ret <= 0)		///server shutdown
	{
	    if (ret < 0)
		perror ("status socketnotifier");
	    //close socket and delete socket noitifier
	    ::close (fd);
	    delete snstatus;
	    snstatus = 0;
	    ///stop timer
	    echotimer->stop ();
	    ///change statusbar interface
	    ///update message
	    message = tr ("Connecting...");
	    ///show message on statusbar
	    for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
		if (tabwidget->indexOf (wd) == tabwidget->currentPageIndex ()) {
		    static_cast < MainWindow * >(qApp->mainWidget ())
			->statusbar->showMessage (message);
		    break;
		}
	    ///
	    return;
	}
	if (strstr (buff, "\n"))
	    break;

	red += ret;
	size -= ret;
    }

    if (buff[0] != 10) {
	char *savept;
	::strtok_r (buff, "\n", &savept);

	int value[6];
	value[0] = atoi (strtok_r (buff, " ", &savept));
	for (int i = 1; i < 6; i++) {
	    value[i] = atoi (strtok_r (NULL, " ", &savept));
	    if (i < 5)
		value[i] = value[i] / 1024;
	}

	static const char format[][10] =
	    { "%d%%", "ur=%dk", "dr=%dk", "us=%dk", "ds=%dk", "peers=%d" };

	for (int i = 0; i < 6; i++) {
	    sprintf (buff, format[i], value[i]);
	    arraymessage[i] = buff;
	}
	///show arraymessage on statusbar
	for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
	    if (tabwidget->indexOf (wd) == tabwidget->currentPageIndex ()) {
		static_cast < MainWindow * >(qApp->mainWidget ())
		    ->statusbar->showMessage (arraymessage);
		break;
	    }
    } else
	printf ("buff=10\n");

    ///singleshot
    echotimer->start (1000, true);
}


void
SopFork::echo ()
{
    bool found = false;
    ///if the current page is within the list, then update data statistics
    for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
	if (tabwidget->indexOf (wd) == tabwidget->currentPageIndex ()) {
	    write (snstatus->socket (), "s\n", sizeof ("s\n"));
	    found = true;
	    break;
	}
    if (found == false)
	echotimer->start (1000, true);
}
